(function (window, T, fn) {
    var ajax = T.ajax = {};
    /**
     * 发送一个ajax请求
     * @author: allstar, erik, berg
     * @name ajax.request
     * @function
     * @grammar ajax.request(url[, options])
     * @param {string}  url 发送请求的url
     * @param {Object}  options 发送请求的选项参数
     * @config {String}     [method]            请求发送的类型。默认为GET
     * @config {Boolean}  [async]           是否异步请求。默认为true（异步）
     * @config {String}     [data]              需要发送的数据。如果是GET请求的话，不需要这个属性
     * @config {Object}     [headers]           要设置的http request header
     * @config {number}   [timeout]       超时时间，单位ms
     * @config {String}     [username]          用户名
     * @config {String}     [password]          密码
     * @config {Function} [onsuccess]       请求成功时触发，function(XMLHttpRequest xhr, string responseText)。
     * @config {Function} [onfailure]       请求失败时触发，function(XMLHttpRequest xhr)。
     * @config {Function} [onbeforerequest] 发送请求之前触发，function(XMLHttpRequest xhr)。
     * @config {Function} [on{STATUS_CODE}]     当请求为相应状态码时触发的事件，如on302、on404、on500，function(XMLHttpRequest xhr)。3XX的状态码浏览器无法获取，4xx的，可能因为未知问题导致获取失败。
     * @config {Boolean}  [noCache]             是否需要缓存，默认为false（缓存），1.1.1起支持。
     * 
     * @meta standard
     * @see ajax.get,ajax.post,ajax.form
     *             
     * @returns {XMLHttpRequest} 发送请求的XMLHttpRequest对象
     */
    ajax.request = function (url, opt_options) {
        var options     = opt_options || {},
            data        = options.data || "",
            async       = !(options.async === false),
            username    = options.username || "",
            password    = options.password || "",
            method      = (options.method || "GET").toUpperCase(),
            headers     = options.headers || {},
            // 基本的逻辑来自lili同学提供的patch
            timeout     = options.timeout || 0,
            eventHandlers = {},
            tick, key, xhr;

        /**
         * readyState发生变更时调用
         * 
         * @ignore
         */
        function stateChangeHandler() {
            if (xhr.readyState == 4) {
                try {
                    var stat = xhr.status;
                } catch (ex) {
                    // 在请求时，如果网络中断，Firefox会无法取得status
                    fire('failure');
                    return;
                }
                
                fire(stat);
                
                // http://www.never-online.net/blog/article.asp?id=261
                // case 12002: // Server timeout      
                // case 12029: // dropped connections
                // case 12030: // dropped connections
                // case 12031: // dropped connections
                // case 12152: // closed by server
                // case 13030: // status and statusText are unavailable
                
                // IE error sometimes returns 1223 when it 
                // should be 204, so treat it as success
                if ((stat >= 200 && stat < 300)
                    || stat == 304
                    || stat == 1223) {
                    fire('success');
                } else {
                    fire('failure');
                }
                
                /*
                 * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
                 * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
                 * function maybe still be called after it is deleted. The theory is that the
                 * callback is cached somewhere. Setting it to null or an empty function does
                 * seem to work properly, though.
                 * 
                 * On IE, there are two problems: Setting onreadystatechange to null (as
                 * opposed to an empty function) sometimes throws an exception. With
                 * particular (rare) versions of jscript.dll, setting onreadystatechange from
                 * within onreadystatechange causes a crash. Setting it from within a timeout
                 * fixes this bug (see issue 1610).
                 * 
                 * End result: *always* set onreadystatechange to an empty function (never to
                 * null). Never set onreadystatechange from within onreadystatechange (always
                 * in a setTimeout()).
                 */
                window.setTimeout(
                    function() {
                        // 避免内存泄露.
                        // 由new Function改成不含此作用域链的 fn.blank 函数,
                        // 以避免作用域链带来的隐性循环引用导致的IE下内存泄露. By rocy 2011-01-05 .
                        xhr.onreadystatechange = fn.blank;
                        if (async) {
                            xhr = null;
                        }
                    }, 0);
            }
        }
        
        /**
         * 获取XMLHttpRequest对象
         * 
         * @ignore
         * @return {XMLHttpRequest} XMLHttpRequest对象
         */
        function getXHR() {
            if (window.ActiveXObject) {
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    try {
                        return new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e) {}
                }
            }
            if (window.XMLHttpRequest) {
                return new XMLHttpRequest();
            }
        }
        
        /**
         * 触发事件
         * 
         * @ignore
         * @param {String} type 事件类型
         */
        function fire(type) {
            type = 'on' + type;
            var handler = eventHandlers[type],
                globelHandler = ajax[type];
            
            // 不对事件类型进行验证
            if (handler) {
                if (tick) {
                  clearTimeout(tick);
                }

                if (type != 'onsuccess') {
                    handler(xhr);
                } else {
                    //处理获取xhr.responseText导致出错的情况,比如请求图片地址.
                    try {
                        xhr.responseText;
                    } catch(error) {
                        return handler(xhr);
                    }
                    handler(xhr, xhr.responseText);
                }
            } else if (globelHandler) {
                //onsuccess不支持全局事件
                if (type == 'onsuccess') {
                    return;
                }
                globelHandler(xhr);
            }
        }
        
        
        for (key in options) {
            // 将options参数中的事件参数复制到eventHandlers对象中
            // 这里复制所有options的成员，eventHandlers有冗余
            // 但是不会产生任何影响，并且代码紧凑
            eventHandlers[key] = options[key];
        }
        
        headers['X-Requested-With'] = 'XMLHttpRequest';
        
        
        try {
            xhr = getXHR();
            
            if (method == 'GET') {
                if (data) {
                    url += (url.indexOf('?') >= 0 ? '&' : '?') + data;
                    data = null;
                }
                if(options['noCache'])
                    url += (url.indexOf('?') >= 0 ? '&' : '?') + 'b' + (+ new Date) + '=1';
            }
            
            if (username) {
                xhr.open(method, url, async, username, password);
            } else {
                xhr.open(method, url, async);
            }
            
            if (async) {
                xhr.onreadystatechange = stateChangeHandler;
            }
            
            // 在open之后再进行http请求头设定
            // FIXME 是否需要添加; charset=UTF-8呢
            if (method == 'POST') {
                xhr.setRequestHeader("Content-Type",
                    (headers['Content-Type'] || "application/x-www-form-urlencoded"));
            }
            
            for (key in headers) {
                if (headers.hasOwnProperty(key)) {
                    xhr.setRequestHeader(key, headers[key]);
                }
            }
            
            fire('beforerequest');

            if (timeout) {
              tick = setTimeout(function(){
                xhr.onreadystatechange = fn.blank;
                xhr.abort();
                fire("timeout");
              }, timeout);
            }
            xhr.send(data);
            
            if (!async) {
                stateChangeHandler();
            }
        } catch (ex) {
            fire('failure');
        }
        
        return xhr;
    };


    /**
     * 发送一个get请求
     * @name ajax.get
     * @function
     * @grammar ajax.get(url[, onsuccess])
     * @param {string}  url         发送请求的url地址
     * @param {Function} [onsuccess] 请求成功之后的回调函数，function(XMLHttpRequest xhr, string responseText)
     * @meta standard
     * @see ajax.post,ajax.request
     *             
     * @returns {XMLHttpRequest}    发送请求的XMLHttpRequest对象
     */
    ajax.get = function (url, onsuccess) {
        return ajax.request(url, {'onsuccess': onsuccess});
    };  

    /**
     * 将一个表单用ajax方式提交
     * @name ajax.form
     * @function
     * @grammar ajax.form(form[, options])
     * @param {HTMLFormElement} form             需要提交的表单元素
     * @param {Object}  [options]                   发送请求的选项参数
     * @config {Boolean} [async]            是否异步请求。默认为true（异步）
     * @config {String}     [username]          用户名
     * @config {String}     [password]          密码
     * @config {Object}     [headers]           要设置的http request header
     * @config {Function} [replacer]            对参数值特殊处理的函数,replacer(string value, string key)
     * @config {Function} [onbeforerequest]     发送请求之前触发，function(XMLHttpRequest xhr)。
     * @config {Function} [onsuccess]       请求成功时触发，function(XMLHttpRequest xhr, string responseText)。
     * @config {Function} [onfailure]       请求失败时触发，function(XMLHttpRequest xhr)。
     * @config {Function} [on{STATUS_CODE}]     当请求为相应状态码时触发的事件，如on302、on404、on500，function(XMLHttpRequest xhr)。3XX的状态码浏览器无法获取，4xx的，可能因为未知问题导致获取失败。
        
     * @see ajax.request
     *             
     * @returns {XMLHttpRequest} 发送请求的XMLHttpRequest对象
     */
    ajax.form = function (form, options) {
        options = options || {};
        var elements    = form.elements,
            len         = elements.length,
            method      = form.getAttribute('method'),
            url         = form.getAttribute('action'),
            replacer    = options.replacer || function (value, name) {
                return value;
            },
            sendOptions = {},
            data = [],
            i, item, itemType, itemName, itemValue, 
            opts, oi, oLen, oItem;
            
        /**
         * 向缓冲区添加参数数据
         * @private
         */
        function addData(name, value) {
            data.push(name + '=' + value);
        }
        
        // 复制发送参数选项对象
        for (i in options) {
            if (options.hasOwnProperty(i)) {
                sendOptions[i] = options[i];
            }
        }
        
        for (i = 0; i < len; i++) {
            item = elements[i];
            itemName = item.name;
            
            // 处理：可用并包含表单name的表单项
            if (!item.disabled && itemName) {
                itemType = item.type;
                itemValue = url.escapeSymbol(item.value);
            
                switch (itemType) {
                // radio和checkbox被选中时，拼装queryString数据
                case 'radio':
                case 'checkbox':
                    if (!item.checked) {
                        break;
                    }
                    
                // 默认类型，拼装queryString数据
                case 'textarea':
                case 'text':
                case 'password':
                case 'hidden':
                case 'select-one':
                    addData(itemName, replacer(itemValue, itemName));
                    break;
                    
                // 多行选中select，拼装所有选中的数据
                case 'select-multiple':
                    opts = item.options;
                    oLen = opts.length;
                    for (oi = 0; oi < oLen; oi++) {
                        oItem = opts[oi];
                        if (oItem.selected) {
                            addData(itemName, replacer(oItem.value, itemName));
                        }
                    }
                    break;
                }
            }
        }
        
        // 完善发送请求的参数选项
        sendOptions.data = data.join('&');
        sendOptions.method = form.getAttribute('method') || 'GET';
        
        // 发送请求
        return ajax.request(url, sendOptions);
    };

    /**
     * 发送一个post请求
     * @name ajax.post
     * @function
     * @grammar ajax.post(url, data[, onsuccess])
     * @param {string}  url         发送请求的url地址
     * @param {string}  data        发送的数据
     * @param {Function} [onsuccess] 请求成功之后的回调函数，function(XMLHttpRequest xhr, string responseText)
     * @meta standard
     * @see ajax.get,ajax.request
     *             
     * @returns {XMLHttpRequest}    发送请求的XMLHttpRequest对象
     */
    ajax.post = function (url, data, onsuccess) {
        return ajax.request(
            url, 
            {
                'onsuccess': onsuccess,
                'method': 'POST',
                'data': data
            }
        );
    };

})(window, T, T.fn);